
	/***********************************************************************************************

		@NAPI
		Module: Storage (native api)

		  t		__ni_load			()
			b		__ni_save			(id, s, ttl)
			v		__ni_read			(id)
			b		__ni_remove		(id)
					__ni_clear		()

	************************************************************************************************/

	//data normalization: __ni_n
	//-------------------------------------------------------------------------------
	//@sys: Explorer  	- error on saving some characters (surrogate pair range: 0xD800-0xDFFF)
	//@sys: Opera				- some control characters [0x00-0x08] are saved but at reading are not placed in
	//										the string. The string is shorter.
	//@sys:	FireFox 3.0	- saves but not read the 0xFEFF character

	jsl.Storage.__ni_re	=	/[\x00-\x08\x0b\x0c\x0e-\x1f\ud800-\udfff\ufeff-\uffff]/g
	jsl.Storage.__ni_f	= function(c) { return "\\u" + ("000" + c.charCodeAt(0).toString(16)).slice(-4) }
	jsl.Storage.__ni_n	= function(s) { return s.replace(this.__ni_re, this.__ni_f) }

	//1-LiquidBox
	//-------------------------------------------------------------------------------
	if(jsl.__sys === "LiquidBox") {

		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_load = function() {
			try {
				var t, a, l, sz

				t = __ni_stg_load(this.__size)

				if(this.__size) {
					sz = 0
					for(a = 0, l = t.length; a < l; a++) sz += t[a].size

					//!
					if(this.__size < sz)	throw jsl.ParamError("storage.BadSize:size")//!
					t.sz = this.__size
				}
				else
					t.sz = 10 * 10485760

				return t
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_save = function(id, s, ttl) {
			try {
				return __ni_stg_save(id, s, ttl)
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_read = function(id) {
			try {
				return __ni_stg_read(id)
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_remove = function(id) {
			try {
				__ni_stg_remove(id)
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_clear = function() {
			try {
				__ni_stg_clear()
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
	}
	//2-Local storage
	//-------------------------------------------------------------------------------
	else if(jsl.__go.localStorage) {

		//predefined size lookup table
		//-------------------------------------------------------------------------------
		jsl.Storage.__ps = {
			//@Sys: Safari 4.0 Firefox Fennec 7.0 - crash on storage write overflow
			"Fennec":						function() { return 5242880 },
			"Firefox":					function() { return 5242880 },
			"Flock":						function() { return 5242880 },
			"Prism":						function() { return 5242880 },

			"Explorer":					function() { return 5000000 },

			"Android-browser":	function() { return 2621440 },
			"Chrome":						function() { return 2621440 },
			"Safari":						function() { return 2621440 },

			"Opera":						function() { return 1965822 },

			"Opera-mobile":			function() { return 393068 	}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_load = function() {
			try {
				var t, s, n, a, l, sz

				//~jsl: to avoid collisions with data stored before using liquid
				s = localStorage.getItem("~jsl")
				t = s ? jsl.Data.deserialize(s) : []

				if(this.__size) {
					if(t.sz !== this.__size) {//!
						if(s) {
							sz	= s.length
							l 	= t.length

							for(a = 0; a < l; a++) sz += t[a].size
							if(this.__size < sz)	throw jsl.ParamError("storage.BadSize:size")
						}//!
						t.sz = this.__size
						localStorage.setItem("~jsl", this.__ni_n(jsl.Data.serialize(t)))
					}
				}
				else {

					n = this.__ps[jsl.info("system.id")]
					n = n && n()

					if(!n) {
						localStorage.clear()
						n = localStorage.remainingSpace

						if(!n) {

							s = Array(500001).join(".")
							a = n = 0

							//250 -> more speed less accurate
							while(s.length > 250)	{
								try 			{	localStorage.setItem("a" + a++, s), n += s.length }
								catch(e) 	{ s = s.slice(0, Math.ceil(s.length / 2)) 					}
							}

							localStorage.clear()
						}
					}

					if(t.sz !== n) {
						t.sz = n
						localStorage.setItem("~jsl", this.__ni_n(jsl.Data.serialize(t)))
					}
				}

				return t
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_save = function(id, s, ttl) {
			try {
				var ts, crc, b, d

				ts 	= this.__ni_n(jsl.Data.serialize(this.__table))
				crc	= jsl.Data.crc32(id)
				d		= this.__ni_n(s)

				try {
					localStorage.setItem(crc, d)
					localStorage.setItem("~jsl", ts)
					b = true
				}
				catch(e) {}
				return b
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_read = function(id) {
			try {
				return localStorage.getItem(jsl.Data.crc32(id))
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_remove = function(id) {
			try {
				localStorage.removeItem(jsl.Data.crc32(id))
				localStorage.setItem("~jsl", this.__ni_n(jsl.Data.serialize(this.__table)))
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_clear = function() {
			try {
				localStorage.clear()
				localStorage.setItem("~jsl", this.__ni_n(jsl.Data.serialize(this.__table)))
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
	}
	//3-Global storage
	//-------------------------------------------------------------------------------
	else if(jsl.__go.globalStorage) {

		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_st = globalStorage[window.location.hostname]
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_load = function() {
			try {
				var t, s, n, a, l, sz, st

				st 	= this.__ni_st
				s 	= st["~jsl"]
				s 	= s ? s.value : null
				t 	= s ? jsl.Data.deserialize(s) : []

				if(this.__size) {
					if(t.sz !== this.__size) {//!
						if(s) {
							sz	= s.length
							l 	= t.length

							for(a = 0; a < l; a++) sz += t[a].size
							if(this.__size < sz)	throw jsl.ParamError("storage.BadSize:size")
						}//!
						t.sz = this.__size
						st["~jsl"] = this.__ni_n(jsl.Data.serialize(t))
					}
				}
				else {

					while(st.length) delete st[st.key(0)]

					n = 5 * 1024 * 1024
					if(t.sz !== n) {
						t.sz = n
						st["~jsl"] = this.__ni_n(jsl.Data.serialize(t))
					}
				}

				return t
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_save = function(id, s) {
			try {
				var t, d, b, c

				//"_" + jsl.Data.crc32(id) -> without the underscore character -> unexpected
				//error at reading time
				t = this.__ni_n(jsl.Data.serialize(this.__table))
				d = this.__ni_n(s)
				c = "_" + jsl.Data.crc32(id)

				try {
					this.__ni_st[c] 			= d
					this.__ni_st["~jsl"] 	= t
					b = true
				}
				catch(e) {}
				return b
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_read = function(id) {
			try {
				var v = this.__ni_st["_" + jsl.Data.crc32(id)]
				return v ? v.value : undefined
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_remove = function(id) {
			try {
				delete this.__ni_st["_" + jsl.Data.crc32(id)]
				this.__ni_st["~jsl"] = this.__ni_n(jsl.Data.serialize(this.__table))
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_clear = function() {
			try {
				var st

				st = this.__ni_st
				while(st.length) delete st[st.key(0)]
				st["~jsl"] = this.__ni_n(jsl.Data.serialize(this.__table))
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
	}
	//4-User-Data
	//-------------------------------------------------------------------------------
	else if(jsl.__sys === "Explorer") {

		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_load = function() {
			try {
				var t, s, d, ds, a, l, vs

				this.__ni_d 			= d = document.createElement("div")
				d.style.behavior	= "url('#default#userData')"
				document.body.appendChild(d) //<-mandatory

				ds	= 65517 * 8
				vs	= this.__ni_vs = {}
				s 	= []

				for(a = 0; a < 8; a++) {
					d.load("jsl" + a)
					s[a] = d.attribute("_")
					if(!s[a]) break
				}

				s = s.join("")

				if(s) {
					//@sys- Explorer: see storage-note.txt
					s = s.replace(/\uFF22/g, "\x22")
					s = s.replace(/\uFF26/g, "\x26")
					s = s.replace(/\uFF3E/g, "\x3E")
					s = s.replace(/\uFF3C/g, "\x3C")

					t = jsl.Data.deserialize(s)

					for(a = 0, l = t.length; a < l; a++) {
						vs[t[a].id] = t[a].v
						delete t[a].v
					}
				}
				else {
					t 		= []
					t.sz 	= ds
				}

				if(this.__size != null && t.sz !== (this.__size || ds)) {
					//!
					if(s && (this.__size || ds) < s.length)	throw jsl.ParamError("storage.BadSize:size")//!

					t.sz = this.__size || ds
					this.__table = t
					this.__ni_save_storage()
				}

				return t
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_save = function(id, s) {
			try {
				//if we read the element after the save, it must be already
				//normalized
				this.__ni_vs[id] = this.__ni_n(s)
				this.__ni_save_storage()
				return true
			}
			catch(e) {
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_read = function(id) {
			try {
				return this.__ni_vs[id]
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_remove = function(id) {
			try {
				delete this.__ni_vs[id]
				this.__ni_save_storage()
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_clear = function() {
			try {
				this.__ni_vs = {}
				this.__ni_save_storage()
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
		//-------------------------------------------------------------------------------
		jsl.Storage.__ni_save_storage = function() {
			try {
				var t, vs, a, l, d, ts, sl, i

				t 	= this.__table
				vs 	= this.__ni_vs

				for(a = 0, l = t.length; a < l; a++)
					t[a].v = vs[t[a].id]

				d 	= this.__ni_d
				ts 	= this.__ni_n(jsl.Data.serialize(t))
				i		= 0

				//@sys - 	Explorer: see storage-note.txt
				ts = ts.replace(/\x22/g, String.fromCharCode(0xFF22))
				ts = ts.replace(/\x26/g, String.fromCharCode(0xFF26))
				ts = ts.replace(/\x3E/g, String.fromCharCode(0xFF3E))
				ts = ts.replace(/\x3C/g, String.fromCharCode(0xFF3C))

			 	for(a = 0; a < 8; a++) {

					sl = ts.slice(i, i + 65517)
					if(sl) {
						i  += 65517
						d.attribute("_",	sl)
					}
					else
						d.removeAttribute("_")

					//no tilde -> jsl can become the name of a file in the
					//filesystem
					d.save("jsl" + a)
				}

				for(a = 0, l = t.length; a < l; a++)
					delete t[a].v
			}
			catch(e) {
				jsl.throwError(e, this, arguments)
			}
		}
	}
	//5-Not supported
	//-------------------------------------------------------------------------------
	else
		jsl.Storage.__ni_load = function() {
			throw jsl.NotSupportedError("NotSupported:Storage")
		}
